﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using DataLayer.DummaDTO;
using Common.DTO;

namespace DataLayer
{
   public static class GetDBInfo
    {
       public static List<GameSession> GetGameSessionListInfoDB(string namn)
       {
           var game = new GameDbEntities().GameSession;

           return
               game.Select(ss => new GameSession {NumOfGameRoundsToPlay = ss.NoOfGameRounds ?? 0, ID = ss.ID, GameID = ss.GameID}).ToList();
       }

       public static List<Game> GetGameListInfoDb()
       {
           var game = new GameDbEntities().Game;

           return game.Select(g => new Game{ ID = g.ID, Name = g.Name }).ToList();

       }

       /// <summary>
       /// Gets all the players in the Db
       /// </summary>
       /// <returns>List of Player Objects</returns>
       public static List<Player> GetAllPlayers()
       {
           var game = new GameDbEntities().Player;

           return game.Select(s => new Player {ID = s.ID, Name = s.Name}).ToList();
       }

       /// <summary>
       /// Returns a player by Id
       /// </summary>
       /// <param name="id"></param>
       /// <returns>Spelare</returns>
       public static Player GetPlayerById(int id)
       {
           try
           {
               var allPlayers = new GameDbEntities().Player;

               var player = allPlayers.Where(s => s.ID == id).SingleOrDefault();
               return new Player { ID = player.ID, Name = player.Name, Mail = player.Mail };
           }
           catch
           {
               return null;
           }
       }

       public static int GetOpponentIdFromSession(int sessionId, int playerId)
       {
           try
           {
               var entities = new GameDbEntities();

               var opponent = entities.PlayerGameSession.FirstOrDefault(x => x.GameSessionID == sessionId && x.PlayerID != playerId);
               return opponent.PlayerID;

           }
           catch (Exception)
           {             
               throw;
           }
       }

       public static Game GetGameById(int id)
       {
           try
           {
               var allGames = new GameDbEntities().Game;
               //var game = allGames.Select(w => w.ID == id).SingleOrDefault();
               var game = allGames.Where(g => g.ID == id).SingleOrDefault();
               return new Game { ID = game.ID, Name = game.Name };
           }
           catch
           {
               return null;
           }
       }

       public static int DetermineRoundWinner(List<PlayerChoiceEntity> playerChoices)
       {
           var playerOne = playerChoices[0];
           var playerTwo = playerChoices[1];

           // TODO : temp solution fix it!
           if (playerOne.Choice == playerTwo.Choice)
           {
               return 0;
           }

           switch (playerOne.Choice)
           {
               case 0:
                   return playerTwo.Choice == 1 ? playerOne.PlayerID : playerTwo.PlayerID;
               case 1:
                   return playerTwo.Choice == 2 ? playerOne.PlayerID : playerTwo.PlayerID;
               case 2:
                   return playerTwo.Choice == 0 ? playerOne.PlayerID : playerTwo.PlayerID;
               default:
                   break;
           }

           return 0;
       }

       //Todo fixa färdigt med hjälp av NoOfGameRounds bl.a
       public static Player DetermineSessionWinner(int gameSessionId)
       {
           var playerChoices = new List<PlayerChoiceEntity>();
           var gameDb = new GameDbEntities();

           var gameRounds = from p in gameDb.PlayerChoice
                            join g in gameDb.GameRound
                            on p.GameRoundID equals g.ID
                            where g.GameSessionID == gameSessionId
                                select p;

           List<int> playerIds = new List<int>();
           int totalGameRounds = gameRounds.Count() / 2;

           for (int roundId = 1; roundId < totalGameRounds; roundId++)
           {
               var round = gameRounds.Where(x => x.GameRoundID == roundId).ToList();

               playerIds.Add(DetermineRoundWinner(round));
           }

           var playerId  = playerIds.GroupBy(item => item).OrderByDescending(g => g.Count()).Select(g => g.Key).First();
           //var gameRoundId = entities.GameRound.FirstOrDefault(x => x.GameSessionID == gameSessionId).ID;

           //playerChoices = entities.PlayerChoice.Where(x => x.GameRoundID == gameRoundId).ToList();
           return GetPlayerById(playerId);
           //var result = DetermineRoundWinner(playerChoices);

           return null;
       }

       /// <summary>
       /// Login the player
       /// </summary>
       /// <param name="login">Players username</param>
       /// <param name="password">Players password</param>
       /// <returns>Returns <see cref="PLayerDto"/> with players details</returns>
       public static Player LoginPlayer(string login, string password)
       {
           var entities = new GameDbEntities();

           var player = entities.Player.FirstOrDefault(p => p.Name == login);

           if (player == null)
           {
               return null;
           }

           return new Player
           {
               ID = player.ID,
               Name = player.Name
           };
       }
	   
       /// <summary>
       /// TODO: Not working
       /// </summary>
       /// <param name="sessionId"></param>
       /// <returns></returns>
	   public static GameRound GetCurrentGameRound (int sessionId)
	   {
            //var entities = new GameDbEntities();
			
            //var gameRounds = entities.GameRound.Where(x => x.ID == sessionId);
			
            //if(gameRounds != null)
            //{
            //    return gameRounds;
            //}
			
            return null;
	   }
	   
       /// <summary>
       /// TODO: Not Working
       /// </summary>
       /// <param name="sessionId"></param>
       /// <returns></returns>
	   public static List<GameRound> GetGameRounds (int sessionId)
	   {
            //var entities = new GameDbEntities();
			
            //var gameRounds = entities.GameRound.Where(x => x.ID == sessionId).ToList();
			
            //if(gameRounds != null)
            //{
            //    return gameRounds;
            //}
			
            return null;
	   }

       public static GameSession GetGameSessionById(int sessionId)
       {
           try
           {
               var session = new GameDbEntities();

               var gs = session.GameSession.Where(s => s.ID == sessionId).FirstOrDefault();

               return new GameSession
               {
                   ID = gs.ID,
                   GameID = (int)gs.GameID,
                   NameOfGame = gs.Game.Name,
                   NumOfGameRoundsToPlay = (int)gs.NoOfGameRounds,
                   ActiveGame = Boolean.Parse(gs.ActiveGame.ToString()),
                   StartDate = DateTime.Now,
                   EndDate = gs.DateEnd ?? null,
                   WinningPlayerID = gs.Winner ?? null
               };
           }
           catch
           {
               return null;
           }
           //throw new NotImplementedException();
       }

       public static bool AddPlayerSession(int playerId, int sessionId)
        {
            try
            {
                //var player = GetDBInfo.GetPlayerById(playerId);
                //var session = GetDBInfo.GetGameSessionById(sessionId);
                if (SaveDBInfo.AddPlayerSession(playerId, sessionId))
                {
                    return true;
                }

                else
                return false;
            }
            catch
            {
                return false;
            }
        }

       public static bool MakePlayerChoice(int gameSessionId, int playerId, int playerChoiceId)
        {
            return SaveDBInfo.MakePlayerChoice(gameSessionId, playerId, playerChoiceId);
        }

       public static List<GameSessionDTO> GetActiveGameSessionInfoDb()
       {

           var session = new GameDbEntities().GameSession.Where(gs => gs.ActiveGame == true);

           return
               session.Select(
                   gsd =>
                   new GameSessionDTO
                   {
                       NumbersOfRounds = (int)gsd.NoOfGameRounds,
                       Id = gsd.ID,
                       GameId = (int)gsd.GameID
                   }).ToList();
       }

       // TODO - Måste ta bort sessioner som spelaren startat - ingen self-join på game
       public static List<GameSessionDTO> GetJoinableGameSessions(int gameId, int playerId)
       {
           var gameDb = new GameDbEntities();

           var sessions = from g in gameDb.GameSession
                      join p in gameDb.PlayerGameSession
                      on g.ID equals p.GameSessionID
                      where g.GameID == gameId && p.PlayerID != playerId && g.Winner == null && g.ActiveGame == false
                      select g;

           return
               sessions.Select(
                   gsd =>
                   new GameSessionDTO
                   {
                       NumbersOfRounds = gsd.NoOfGameRounds ?? 1,
                       Id = gsd.ID,
                       GameId = (int)gsd.GameID
                   }).ToList();
       }

       /// <summary>
       /// Returns players gamesessions
       /// </summary>
       /// <param name="playerId">Players id</param>
       /// <returns>GameSession Objects</returns>
       public static List<GameSessionEntity> GetPlayersGameSessions(int playerId)
       {
           var entities = new GameDbEntities();

           var playerSession = (from s in entities.GameSession
                               join p in entities.PlayerGameSession
                               on s.ID equals p.GameSessionID
                               where p.PlayerID == playerId
                                select s).ToList();

           return playerSession;
       }

       // Ska verkligen NoOfGameRounds va nullable? spela som inte har omgångar kommer inte heller att leta efter antalet omgångar?
       public static int GetTotaltOfGameRounds(int gameSessionId)
       {
           var entitites = new GameDbEntities();

           return entitites.GameSession.FirstOrDefault(g => g.ID == gameSessionId).NoOfGameRounds ?? 0;
       }

       /// <summary>
       /// Hämtar ut hur många omgångar som spelats hittills
       /// </summary>
       /// <param name="gameSessionId"></param>
       /// <returns></returns>
       public static int GetNumberOfPlayedGameRounds(int gameSessionId)
       {
           var entities = new GameDbEntities();

           return entities.GameRound.Count(x => x.GameSessionID == gameSessionId);
       }
    }
}
